﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Lidgren.Network;
using Microsoft.Xna.Framework;

namespace D2D2.SharedInterfaces.Networking
{
    public class PlayerObject : BaseMessage
    {
        private float _currentAction;
        private float _currentLive;

        private readonly Random _rand = new Random();
        private float _timeSinceHit;
        private float _targetLive;
        private float _timeSinceAction;
        private float _targetAction;

        public PlayerObject()
        {

        }

        public PlayerObject(NetIncomingMessage message)
            : base(message)
        {

        }

        public PlayerObject(NetIncomingMessage message, NetConnection connection)
            : base(message, connection)
        {

        }

        public float TotalLive { get; set; }
        public float TotalAction { get; set; }
        public float LiveRegen { get; set; }
        public float ActionRegen { get; set; }

        public float LiveHitTime { get; set; }
        public bool InDecreasingLive { get; set; }

        public float ActionHitTime { get; set; }
        public bool InDecreasingAction { get; set; }

        public float CurrentAction
        {
            get { return _currentAction; }
            set { _currentAction = value > TotalAction ? TotalAction : value; }
        }

        public float CurrentLive
        {
            get { return _currentLive; }
            set { _currentLive = value > TotalLive ? TotalLive : value; }
        }

        public int MinDamage { get; set; }

        public int MaxDamage { get; set; }


        public int GetDamage()
        {
            return _rand.Next(MinDamage, MaxDamage + 1);
        }

        public int GetAction()
        {
            return _rand.Next(20, 31);
        }

        public bool CalculateLive(float elapsed)
        {
            if (InDecreasingLive)
            {
                _timeSinceHit += elapsed;
                float remainingTime = LiveHitTime - (_timeSinceHit - elapsed);

                float deltaLive = (CurrentLive - _targetLive) * elapsed / remainingTime;

                float calculatedLive = CurrentLive - deltaLive;

                if (calculatedLive <= _targetLive)
                {
                    CurrentLive = _targetLive;
                    _targetLive = TotalLive;
                    InDecreasingLive = false;
                    _timeSinceHit = 0;
                }
                else
                    CurrentLive = MathHelper.Max(_targetLive, calculatedLive);

                if (calculatedLive <= 0)
                {
                    Alive = false;
                }

                return true;
            }

            if (CurrentLive < TotalLive)
            {
                CurrentLive = MathHelper.Min(CurrentLive + elapsed * LiveRegen, TotalLive);
                return true;
            }

            return false;
        }

        public bool CalculateAction(float elapsed)
        {
            if (InDecreasingAction)
            {
                _timeSinceAction += elapsed;
                float remainingTime = ActionHitTime - (_timeSinceAction - elapsed);

                float deltaAction = (CurrentAction - _targetAction) * elapsed / remainingTime;

                float calculatedAction = CurrentAction - deltaAction;

                if (calculatedAction <= _targetAction)
                {
                    CurrentAction = _targetAction;
                    _targetAction = TotalAction;
                    InDecreasingAction = false;
                    _timeSinceAction = 0;
                }
                else
                    CurrentAction = MathHelper.Max(_targetAction, calculatedAction);

                return true;
            }

            if (CurrentAction < TotalAction)
            {
                CurrentAction = MathHelper.Min(CurrentAction + elapsed * ActionRegen, TotalAction);
                return true;
            }

            return false;
        }

        public void DecreaseLive(int damage)
        {
            _targetLive = TotalLive - damage;
            InDecreasingLive = true;
            _timeSinceHit = 0;
        }

        public void DecreaseAction(int action)
        {
            _targetAction = TotalAction - action;
            InDecreasingAction = true;
            _timeSinceAction = 0;
        }

        public int Level { get; set; }

        public int Money { get; set; }

        public bool Alive { get; set; }

        public int Strength { get; set; }
        public int Dexterity { get; set; }
        public int Energy { get; set; }
        public int Intelligence { get; set; }

        public override GameMessageType MessageType
        {
            get { return GameMessageType.PlayerState; }
        }

        public override void Encode(NetOutgoingMessage message)
        {
            message.Write(Id);
            message.Write(Strength);
            message.Write(Dexterity);
            message.Write(Energy);
            message.Write(Intelligence);
            message.Write(TotalLive);
            message.Write(CurrentLive);
            message.Write(TotalAction);
            message.Write(CurrentAction);
            message.Write(Level);
            message.Write(Alive);
            message.Write(MinDamage);
            message.Write(MaxDamage);
            message.Write(LiveHitTime);
            message.Write(ActionHitTime);
        }

        public override void Decode(NetIncomingMessage message)
        {
            Id = message.ReadInt64();
            Strength = message.ReadInt32();
            Dexterity = message.ReadInt32();
            Energy = message.ReadInt32();
            Intelligence = message.ReadInt32();
            TotalLive = message.ReadFloat();
            CurrentLive = message.ReadFloat();
            TotalAction = message.ReadFloat();
            CurrentAction = message.ReadFloat();
            Level = message.ReadInt32();
            Alive = message.ReadBoolean();
            MinDamage = message.ReadInt32();
            MaxDamage = message.ReadInt32();
            LiveHitTime = message.ReadFloat();
            ActionHitTime = message.ReadFloat();
        }

        public PlayerObject Clone()
        {

            PlayerObject player = new PlayerObject
                                      {
                                          Id = Id,
                                          Strength = Strength,
                                          Dexterity = Dexterity,
                                          Energy = Energy,
                                          Intelligence = Intelligence,
                                          TotalLive = TotalLive,
                                          CurrentLive = CurrentLive,
                                          TotalAction = TotalAction,
                                          CurrentAction = CurrentAction,
                                          Level = Level,
                                          Alive = Alive,
                                          MinDamage = MinDamage,
                                          MaxDamage = MaxDamage,
                                          LiveHitTime = LiveHitTime,
                                          ActionHitTime = ActionHitTime
                                      };

            return player;
        }
    }
}
